﻿/* Copyright (c) 2010 EPiServer AB
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using EPiServer.Configuration;
using EPiServer.Core;
using EPiServer.Core.Html;
using EPiServer.DataAbstraction;
using EPiServer.Filters;
using EPiServer.Municipality.Configuration;
using EPiServer.Municipality.Web.Mail;
using EPiServer.PlugIn;
using Constants=EPiServer.Municipality.Configuration.Constants;

namespace EPiServer.Municipality.Web.Schedulers {
    /// <summary>
    /// Summary description for UpdatePageNotifierJob.
    /// </summary>
    /// <remarks>
    /// </remarks>
    [ScheduledPlugIn(LanguagePath = "/municipality/schedulers/updatedpagenotifier")]
    public class UpdatePageNotifierJob {
        /* *******************************************************************
        *  Properties 
        * *******************************************************************/
        #region protected static SiteSettings Config
        /// <summary>
        /// Gets the Config of the NewPageNotifierJob
        /// </summary>
        /// <value></value>
        protected static SiteSettings Config {
            get {
                if (_config == null) {
                    _config = new SiteSettings();
                    PlugInSettings.AutoPopulate(_config);
                }
                return _config;
            }
        }
        private static SiteSettings _config;
        #endregion
        #region private static PageReference RootPages
        /// <summary>
        /// Gets the RootPages of the ResponsibleUpdatePageJob
        /// </summary>
        /// <value></value>
        private static PageReferenceCollection RootPages {
            get {
                var value = Config.RootPages;
                var rootPages = new PageReferenceCollection();
                if (!string.IsNullOrEmpty(value)) {
                    rootPages = new PageReferenceCollection();
                    var values = value.Split(new[] { ',' });
                    if (values.Length > 0) {
                        foreach (var s in values) {
                            rootPages.Add(new PageReference((int.Parse(s))));
                        }
                    }
                    return rootPages;
                }
                rootPages.Add(PageReference.StartPage);
                return rootPages;
            }
        }
        #endregion
        #region private static string Receiver
        /// <summary>
        /// Gets the Receiver of the UpdatePageNotifierJob
        /// </summary>
        /// <value></value>
        private static string Receiver {
            get {
                var receiver = Config.Receiver;
                if (string.IsNullOrEmpty(receiver) || receiver.IndexOf("@") <= 0) {
                    return Config.WebmasterEmail;
                }
                return receiver;
            }
        }
        #endregion
        #region private static string Sender
        /// <summary>
        /// Gets the Sender of the UpdatePageNotifierJob
        /// </summary>
        /// <value></value>
        private static string Sender {
            get {
                var sender = Config.Sender;
                if (string.IsNullOrEmpty(sender) || sender.IndexOf("@") <= 0) {
                    return Config.SystemEmail;
                }
                return sender;
            }
        }
        #endregion
        #region private static List<int> IncludedPageTypes
        /// <summary>
        /// Gets the IncludedPageTypes of the UpdatePageNotifierJob
        /// </summary>
        /// <value></value>
        private static List<int> IncludedPageTypes {
            get {
                var value = Config.IncludedPageTypes;
                if (!string.IsNullOrEmpty(value)) {
                    var values = value.Split(new[] { ',' });
                    if (values.Length > 0) {
                        _includedPageTypes = new List<int>();
                        foreach (var s in values) {
                            _includedPageTypes.Add(int.Parse(s));
                        }
                    }
                }
                return _includedPageTypes;
            }
        }
        private static List<int> _includedPageTypes;
        #endregion
        #region private static string PropertyReviewed
        /// <summary>
        /// Gets the PropertyReviewed of the UpdatePageNotifierJob
        /// </summary>
        /// <value></value>
        private static string PropertyReviewed {
            get {
                return Constants.PageReviewProperty;
            }
        }
        #endregion
        #region private static TimeSpan NotChangedPagesSince
        /// <summary>
        /// Gets the NotChangedPagesSince of the UpdatePageNotifierJob
        /// </summary>
        /// <value></value>
        private static TimeSpan NotChangedPagesSince {
            get {
                return TimeSpan.FromDays(Config.ChangedSince);
            }
        }
        #endregion
        #region private static string Language
        /// <summary>
        /// Gets the Language of the UpdatePageNotifierJob
        /// </summary>
        /// <value></value>
        private static string Language {
            get {
                var language = Config.LanguageId;
                if (!string.IsNullOrEmpty(language)) {
                    return language;
                }
                return "sv";
            }
        }
        #endregion
        /* *******************************************************************
         *  Static methods 
         * *******************************************************************/
        #region public static string Execute()
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static string Execute() {
            try {
                if (IncludedPageTypes == null || IncludedPageTypes.Count == 0)
                    return "[OK] " + LanguageManager.Instance.Translate("/municipality/schedulers/updatedpagenotifier/nopagetypes", Language);
                
                // First sort out all pages that are old and where PropertyReviewed is never set (null)
                var propertyCriteriaCollection1 = new PropertyCriteriaCollection();
                var propertyCriteria1 = new PropertyCriteria {Name = "PageChanged"};
                var dateTime = DateTime.Today;
                propertyCriteria1.Value = dateTime.Subtract(NotChangedPagesSince).ToString();
                propertyCriteria1.Condition = CompareCondition.LessThan;
                propertyCriteria1.Type = PropertyDataType.Date;
                propertyCriteria1.Required = true;
                propertyCriteriaCollection1.Add(propertyCriteria1);

                if (!string.IsNullOrEmpty(PropertyReviewed)) {
                    var propertyCriteria2 = new PropertyCriteria
                                                {
                                                    Name = PropertyReviewed,
                                                    IsNull = true,
                                                    Type = PropertyDataType.Date,
                                                    Required = true
                                                };
                    propertyCriteriaCollection1.Add(propertyCriteria2);
                }

                var languages = LanguageBranch.ListEnabled();

                var collOldPages = new PageDataCollection();

                foreach (var branch in languages) {
                    var lang = new LanguageSelector(branch.LanguageID);
                    foreach (var rootReference in RootPages) {
                        var langPages = DataFactory.Instance.FindPagesWithCriteria(rootReference, propertyCriteriaCollection1, branch.LanguageID, lang);
                        collOldPages.Add(langPages);
                    }
                }

                // Second, sort out all pages that are old, PropertyReviewed is set and the date in
                // PropertyReviewed is old
                var propertyCriteriaCollection2 = new PropertyCriteriaCollection();
                var propertyCriteria3 = new PropertyCriteria
                                            {
                                                Name = "PageChanged",
                                                Value = dateTime.Subtract(NotChangedPagesSince).ToString(),
                                                Condition = CompareCondition.LessThan,
                                                Type = PropertyDataType.Date,
                                                Required = true
                                            };
                propertyCriteriaCollection2.Add(propertyCriteria3);


                if (!string.IsNullOrEmpty(PropertyReviewed)) {
                    var propertyCriteria4 = new PropertyCriteria
                                                {
                                                    Name = PropertyReviewed,
                                                    Value = dateTime.Subtract(NotChangedPagesSince).ToString(),
                                                    Condition = CompareCondition.LessThan,
                                                    Type = PropertyDataType.Date,
                                                    Required = true
                                                };
                    propertyCriteriaCollection2.Add(propertyCriteria4);
                }

                foreach (var branch in languages) {
                    var lang = new LanguageSelector(branch.LanguageID);
                    foreach (var rootReference in RootPages) {
                        var langPages = DataFactory.Instance.FindPagesWithCriteria(rootReference, propertyCriteriaCollection2, branch.LanguageID, lang);
                        collOldPages.Add(langPages);
                    }
                }

                for (var i = 0; i < collOldPages.Count; i++) {
                    if (!IncludedPageTypes.Contains(collOldPages[i].PageTypeID)) {
                        collOldPages.RemoveAt(i);
                        i--;
                    }
                }

                Send(Receiver, collOldPages);

                return "[OK] " + String.Format(LanguageManager.Instance.Translate("/municipality/schedulers/updatedpagenotifier/returnstring", Language), collOldPages.Count, Receiver);
            } catch (Exception ex) {
                return "[FAILED] " + ex.Message;
            }
        }
        #endregion
        #region private static void Send(string receiver, PageDataCollection oldPages)
        /// <summary>
        /// The actual method called to send message
        /// </summary>
        /// <param name="receiver"></param>
        /// <param name="oldPages"></param>
        /// <returns></returns>
        private static void Send(string receiver, PageDataCollection oldPages) {

            SortByLatestDate(oldPages);

            var subject = String.Format(LanguageManager.Instance.Translate("/municipality/schedulers/updatedpagenotifier/subject", Language), Settings.Instance.SiteDisplayName);
            var introduction = LanguageManager.Instance.Translate("/municipality/schedulers/updatedpagenotifier/introduction", Language);

            var builder = new StringBuilder();

            builder.Append("<p class=\"introduction\">");
            builder.Append(introduction);
            builder.Append("</p>");

            builder.Append("<ul>");
            foreach (var oldPage in oldPages) {
                builder.Append("<li>");

                builder.Append("<a href=\"");
                builder.Append(MailUtil.GeneratePageUrl(oldPage));
                builder.Append("\">");
                builder.Append(oldPage.PageName);
                builder.Append("</a>");
                builder.Append("<br />");

                //Date and user that saved the page 
                builder.Append("<span class=\"date\">");
                builder.Append(LanguageManager.Instance.Translate("/municipality/schedulers/updatedpagenotifier/changedby", Language));
                builder.Append(oldPage.ChangedBy + " ");
                
                var changedDate = (DateTime) oldPage["PageChanged"];
                var reviewedDate = DateTime.MinValue;
                if (oldPage[PropertyReviewed] != null)
                    reviewedDate = (DateTime)oldPage[PropertyReviewed];
                if (changedDate < reviewedDate)
                    builder.Append(reviewedDate.ToShortDateString());
                else
                    builder.Append(changedDate.ToShortDateString());
                builder.Append("</span>");
                builder.Append("<br />");

                //Introduction text
                string pageBody = null;
                if (oldPage["MainIntro"] != null) {
                    pageBody = oldPage.Property["MainIntro"].ToWebString();
                } else {
                    string strippedBody = TextIndexer.StripHtml(oldPage["MainBody"] as string, 255);
                    if (strippedBody != null) {
                        pageBody = strippedBody;
                    }
                }
                if (!string.IsNullOrEmpty(pageBody)) {
                    builder.Append(pageBody);
                    builder.Append("<br />");
                }

                //Editlink
                builder.Append("<a class=\"textlink\" href=\"");
                builder.Append(UriSupport.UIUrl + "edit/default.aspx?id=" + oldPage.PageLink.ID);
                builder.Append("\">");
                builder.Append(LanguageManager.Instance.Translate("/municipality/misc/editpage", Language));
                builder.Append("</a>");
                builder.Append("<br />");
                builder.Append("<br />");

                builder.Append("</li>");
            }
            builder.Append("</ul>");

            MailUtil.SendHtmlMail(subject, builder.ToString(), receiver, Sender);
        }
        #endregion
        #region private static void SortByLatestDate(PageDataCollection pages)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pages"></param>
        private static void SortByLatestDate(PageDataCollection pages) {
            var filter = new FilterSort(FilterSortOrder.PublishedDescending);
            filter.Filter(null, new FilterEventArgs(pages));
        }
        #endregion
    }
}